package com.mrd.util;

import com.mrd.util.itf.IFileContentOperation;

import org.apache.commons.lang3.StringUtils;

import sun.nio.ch.FileChannelImpl;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigInteger;
import java.net.URL;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * <p> application name: sample <p> copyright: Copyright@2012 明睿达科技有限公司
 */

/**
 * @author qiul
 */
public class FileUtil {
    private static Logger log = Logger.getLogger(FileUtil.class.getName());

    /**
     * 以utf-8为字符集读取文件并获取文件内容
     *
     * @param fileName 文件名
     * @return 文件内容
     * @throws Exception 读取文件发生错误时出现该错误
     */
    public static String getFileContent(String fileName) throws Exception {
        return getFileContent(fileName, "utf-8");
    }

    /**
     * 获取文件内容
     *
     * @param fileName    文件名
     * @param charsetName 文件字符集
     * @throws Exception 读取文件发生错误时出现该错误
     */
    public static String getFileContent(String fileName, String charsetName) throws Exception {
        if (fileName.indexOf(".jar!") != -1) {
            InputStream is = FileUtil.class.getResourceAsStream(fileName.substring(fileName.indexOf(".jar!") + 5));
            return getFileContent(is, charsetName);
        } else {
            File file = new File(fileName);
            return getFileContent(file, charsetName);
        }
    }

    /**
     * 从指定流中读取文件内容
     *
     * @param is          输入流
     * @param charsetName 字符集
     * @param ifco        内容处理接口
     */
    public static List<Object> getFileContent(InputStream is, String charsetName, IFileContentOperation<?> ifco) throws Exception {
        List<Object> list = new ArrayList<Object>();
        if (charsetName == null || "".equals(charsetName)) {
            charsetName = "utf-8";
        }
        BufferedReader br = new BufferedReader(new InputStreamReader(is, charsetName));
        String tmp = null;
        try {
            while ((tmp = br.readLine()) != null) {
                if (ifco == null) {
                    list.add(tmp);
                } else {
                    Object o = ifco.operationContent(tmp);
                    if (o != null) {
                        list.add(o);
                    }
                }
            }
        } catch (Exception e) {
            throw e;
        } finally {
            if (br != null) {
                br.close();
            }
        }
        return list;
    }

    /**
     * 获取文件内容
     *
     * @param file        文件对象
     * @param charsetName 文件字符集
     * @return 文件内容
     * @throws Exception 读取文件发生错误时出现该错误
     */
    public static List<Object> getFileContent(File file, String charsetName, IFileContentOperation<?> ifco) throws Exception {
        List<Object> list = new ArrayList<Object>();
        if (file == null) {
            return list;
        }
        if (!file.exists()) {
            return list;
        }
        return getFileContent(new FileInputStream(file), charsetName, ifco);
    }

    /**
     * 获取文件内容
     *
     * @param file        文件名
     * @param charsetName 文件字符集
     * @throws Exception 读取文件发生错误时出现该错误
     */

    public static String getFileContent(File file, String charsetName) throws Exception {
        List<Object> list = getFileContent(file, charsetName, null);
        StringBuffer sb = new StringBuffer();
        for (Object object : list) {
            sb.append(object);
            sb.append("\n");
        }
        return sb.toString();
    }

    /**
     * 获取文件内容
     *
     * @param is          文件流
     * @param charsetName 字符集
     */
    public static String getFileContent(InputStream is, String charsetName) throws Exception {
        List<Object> list = getFileContent(is, charsetName, null);
        StringBuffer sb = new StringBuffer();
        for (Object object : list) {
            sb.append(object);
            sb.append("\n");
        }
        return sb.toString();
    }

    /**
     * 获取文件内容
     *
     * @param file 文件名
     * @throws Exception 读取文件发生错误时出现该错误
     */

    public static String getFileContent(File file) throws Exception {
        return getFileContent(file, "utf-8");
    }

    /**
     * 以utf-8字符集形式,将数据写入文件中
     *
     * @param filePath    文件路径
     * @param fileContent 数据内容
     */
    public static void writeFile(String filePath, String fileContent) throws IOException {
        writeFile(filePath, fileContent, "utf-8");
    }

    /**
     * 以utf-8字符集形式,将数据写入文件中
     *
     * @param file        文件
     * @param fileContent 数据内容
     */
    public static void writeFile(File file, String fileContent) throws IOException {
        writeFile(file, fileContent, "utf-8");
    }

    /**
     * 将数据写入文件中
     *
     * @param filePath    文件路径
     * @param fileContent 数据内容
     * @param csn         字符集
     */
    public static void writeFile(String filePath, String fileContent, String csn) throws IOException {
        File file = new File(filePath);
        writeFile(file, fileContent, csn);
    }

    /**
     * 将数据写入文件中，如果文件存在，则会覆盖文件内容
     *
     * @param file        文件
     * @param fileContent 数据内容
     * @param csn         字符集
     */
    public static void writeFile(File file, String fileContent, String csn) throws IOException {
        // if(file.exists()) {
        // file.delete();
        // }else{
        file.createNewFile();
        PrintWriter pw = new PrintWriter(file, csn);
        pw.write(fileContent);
        pw.flush();
        pw.close();
        // }
    }

    /**
     * 获取配置文件路径，如果获取不到则获取"项目路径\WEB-INF\classes\配置文件"这个路径
     */
    public static String getPropertiesPath(String source) {
        URL uri = new FileUtil().getClass().getClassLoader().getResource(source);
        String file = "";
        if (uri == null) {
            File f = new File(".");
            try {
                file = f.getCanonicalPath() + "\\bin\\" + source;
                if (!new File(file).exists()) {
                    file = f.getCanonicalPath();
                    file += "\\target\\classes\\" + source;
                }
                if (!new File(file).exists()) {
                    file = f.getCanonicalPath();
                    file += "\\WEB-INF\\classes\\" + source;
                }
            } catch (IOException e) {
                try {
                    log.log(Level.WARNING, "读取配置文件错误，文件为：" + file, e);
                } catch (Exception e1) {
                }
            }
        } else {
            file = uri.getFile();
        }
        if (file != null && !"".equals(file)) {
            file.replaceAll("%20", " ");// 处理空格会转换为%20的问题
        }
        return file;
    }

    /**
     * 将文件剪切至某个目录下
     *
     * @param fileName    文件名
     * @param filePath    文件夹路径
     * @param newFilePath 新文件夹路径
     * @return 返回移动后的文件对象，移动失败返回null
     */
    public static File moveFile(String fileName, String filePath, String newFilePath) {
        return moveAndRenameFile(fileName, filePath, newFilePath, null);
    }

    /**
     * 将文件移动到某个目录并重命名
     *
     * @param fileName    文件名
     * @param filePath    文件夹路径
     * @param newFilePath 新文件夹路径
     * @param newName     新文件名
     * @return 返回移动后的文件对象，移动失败返回null
     */
    public static File moveAndRenameFile(String fileName, String filePath, String newFilePath, String newName) {
        File oldFile = new File(filePath + File.separator + fileName);
        return moveAndRenameFile(oldFile, newFilePath, newName);
    }

    /**
     * 将文件移动到某个目录并重命名
     *
     * @param file        文件
     * @param newFilePath 新文件夹路径
     * @param newName     新文件名
     * @return 返回移动后的文件对象，移动失败返回null
     */
    public static File moveAndRenameFile(File file, String newFilePath, String newName) {
        if (file.exists()) {
            if (newName == null || "".equals(newName)) {
                newName = file.getName();
            }
            File newFile = new File(newFilePath + File.separator + newName);
            if (file.renameTo(newFile)) {
                return newFile;
            }
            return null;
        } else {
            return null;
        }
    }

    /**
     * 将文件剪切至某个目录下
     *
     * @param file        文件
     * @param newFilePath 新文件夹路径
     * @return 返回移动后的文件对象，移动失败返回null
     */
    public static File moveFile(File file, String newFilePath) {
        return moveAndRenameFile(file, newFilePath, null);
    }

    /**
     * 读取ini/properties配置文件，格式为 键=值,以#为注释
     */
    public static Map<String, String> readIni(String file) {
        if (file.indexOf(".jar!") != -1) {
            InputStream is = FileUtil.class.getResourceAsStream(file.substring(file.indexOf(".jar!") + 5));
            return readIni(is);
        }
        return readIni(new File(file));
    }

    /**
     * 从jar中读取配置文件
     */
    public static Map<String, String> readIniFromJar(String AbsolutePath) {
        InputStream is = FileUtil.class.getResourceAsStream(AbsolutePath);
        return readIni(is);
    }

    /**
     * 从文件系统中读取配置文件
     */
    public static Map<String, String> readIni(File file) {
        try {
            InputStream is = new FileInputStream(file);
            return readIni(is);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return new HashMap<String, String>();
    }

    /**
     * 读取ini/properties配置文件，格式为 键=值,以#为注释
     */
    private static Map<String, String> readIni(InputStream is) {
        Map<String, String> iniMap = new HashMap<String, String>();
        try {
            List<Object> keys = getFileContent(is, "utf-8", new IFileContentOperation<Object>() {
                @Override
                public Object operationContent(String content) {
                    if (StringUtils.isEmpty(content) || content.startsWith("#")) {
                        return "";
                    }
                    return content.trim();
                }
            });
            for (Object object : keys) {
                String key = (String) object;
                if (StringUtils.isEmpty(key)) {
                    continue;
                }
                key = key.trim();
                int index = key.indexOf("=");
                if (index != key.length() - 1) {
                    iniMap.put(key.substring(0, index).trim(), key.substring(index + 1).trim());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return iniMap;
    }

    /**
     * 获取文件MD5值
     */
    public static String getMD5(File file) {
        String value = null;
        FileChannel fileChannel = null;
        MappedByteBuffer byteBuffer = null;
        try {
            fileChannel = new FileInputStream(file).getChannel();
            byteBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, file.length());
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            md5.update(byteBuffer);
            BigInteger bi = new BigInteger(1, md5.digest());
            value = bi.toString(16);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fileChannel != null) {
                    fileChannel.close();
                }
                //关闭MappedByteBuffer
                Method m = FileChannelImpl.class.getDeclaredMethod("unmap", MappedByteBuffer.class);
                m.setAccessible(true);
                m.invoke(FileChannelImpl.class, byteBuffer);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } finally {
                fileChannel = null;
            }
        }
        return value;
    }
}
